PIC16F877A(PICマイコン) ~ C言語 ~
TEditorMX(テキストエディタ)をご活用頂ければと思いまして、『PIC16F877A(PICマイコン) ~ C言語 ~』です。
アセンブリ言語バージョンと同等のC言語プログラムをご紹介致します。
PICマイコンをやってみたところ、やはりPICのハードウェアとアセンブリ言語をある程度理解しないとC言語でプログラミングできないと思います。
なのでその辺の知識が無い方はまずアセンブリ言語バージョンの方をご覧になって下さいね。
ここで使用したCコンパイラはMicrochipさんの XC8 ver2.05(無償版)です。
MPLAB X IDE 同様、頑張ってインストールして下さいね。
なお、XC8はコマンドラインからも使用できますのでTEditorMXのコンパイル機能を使ってコンパイルできます。
ちなみに最初はSDCCを使おうと思ったのですが、コンパイルすると原因不明のワーニングが出力されるため断念しました。
PICは種類がたくさんあるため、まだ十分に対応できていないのかもしれません。
CPU周りの回路はアセンブリ言語バージョンのものと全く同じものです。
ですので基板も同じものを使用しました。
(1)ソースファイル
ソースファイルのアーカイブはioc.zipとserialc.zipの2つです(下線部をクリックしてダウンロードして下さいね)。
ioc.zipはスイッチの入力とLEDへの出力をC言語に書き換えたものです。
serialc.zipはシリアル通信をC言語に書き換えたものです。
それぞれのソースファイルには対応するアセンブリ言語コードをコメントとして記述しておきましたのでご覧ください。
(2)環境設定
環境設定はインストールしたCコンパイラ(XC8)をコマンドラインから実行できるようにパスを通すバッチファイルを作成(修正)します。
アーカイブに含めた setpath.bat は私(管理人)がXC8をデフォルトでインストールしたときのものです。
ご自分の環境に合わせてXC8のbinフォルダにパスを通して下さい。
setpath.bat
set Path="C:\Program Files (x86)\Microchip\xc8\v2.05\bin";%Path% ※下線部をご自分の環境に合わせて書き換えて下さい
setpath.batを作成(修正)したらコマンドプロンプトを開き、setpath.batを実行後xc8と入力して実行してみて下さい。 正しくパスが通っていれば下図のような感じに表示されると思います。
実際にやってみたときの様子
(3)コンパイル
XC8のbinフォルダにパスを通すことができればコンパイル用バッチファイル(compile.bat)が実行可能です。
ただし、compile.batはソースファイルを格納しているフォルダ(src)の親フォルダをカレントフォルダにして実行する必要があります。
ちょっと面倒ですが、これはXC8が多くのファイルを出力してくるため、ソースファイルと分離したいがための対策です。
コマンドプロンプトを開いて上の項で作成(修正)したsetpath.batを実行後、更にcompile.batを実行してみて下さい。
上手くいけば下図のような感じになると思います。
またmain.hexファイル(PICに書き込むファイル)が作成されていることも確認してみて下さい。
実際にやってみたときの様子
XC8のコンパイルスイッチですが、-E オプションを指定するとエラーが発生した各行にファイル名が出力されますのでTEditorMXでタグジャンプできるようになります。
逆に -E オプションを指定しないとファイル名が取得できないためTEditorMXでタグジャンプできません。
--ASMLIST オプションを付けますとリストファイル(.lst)が作成されます。
必要な方は指定しましょう。
(4)C言語ソースファイル
アーカイブをダウンロードするのが面倒な人のためにソースプログラムをダラダラと掲載してみることにします。
main.c(ioc.zip)
/* * I/O入出力サンプルプログラム * * アセンブリ言語をC言語に置き換えただけのものです。 * 元のアセンブラソースをコメントとして記述してあります。 */ // configuration bits (FOSCは発振器の種類・周波数で変化します。その他はOFFでとりあえずOKです) // __CONFIG _FOSC_HS & _WDTE_OFF & _PWRTE_OFF & _BOREN_OFF & _LVP_OFF & _CPD_OFF & _WRT_OFF & _CP_OFF #pragma config FOSC = HS // Oscillator Selection bits (HS oscillator) #pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled) #pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled) #pragma config BOREN = OFF // Brown-out Reset Enable bit (BOR disabled) #pragma config LVP = OFF // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming) #pragma config CPD = OFF // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off) #pragma config WRT = OFF // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control) #pragma config CP = OFF // Flash Program Memory Code Protection bit (Code protection off) #include <xc.h> //------------------------------------------------------------- // 初期化 //------------------------------------------------------------- void init( void ) { /* ; BANK0選択 BCF STATUS, RP0 BCF STATUS, RP1 ;念のためI/Oポート出力を0に CLRF PORTA CLRF PORTB CLRF PORTC CLRF PORTD CLRF PORTE */ // 念のためI/Oポート出力を0に PORTA = 0; PORTB = 0; PORTC = 0; PORTD = 0; PORTE = 0; /* ;BANK1を選択 BSF STATUS, RP0 ;PORTDを入力に設定 MOVLW 0xff MOVWF TRISD */ // PORTDを入力に設定 TRISD = 0xff; /* ;PORTD以外をすべて出力に設定 CLRF TRISA CLRF TRISB CLRF TRISC CLRF TRISE */ // PORTD以外をすべて出力に設定 TRISA = 0; TRISB = 0; TRISC = 0; TRISE = 0; /* ;BANK0を選択 BCF STATUS, RP0 */ } //------------------------------------------------------------- // メインループ // // ※MPLAB X IDE ではmain関数はint型の戻り値を返すようですが、 // ここでは不要と思われるのでvoid型にしてあります。 //------------------------------------------------------------- void main( void ) { /* ;PORTDを読み込み、そのままPORTBに出力 MOVF PORTD, w MOVWF PORTB GOTO main END */ unsigned char w; init(); // PORTDを読み込み、そのままPORTBに出力 for(;;) { w = PORTD; PORTB = w; } }
main.c(serialc.zip)
/* * シリアル通信サンプルプログラム * * 機能:パソコンとRS-232Cのクロスケーブルで接続してターミナルソフトで文字をMCU側に送ると * オウム返しで文字を送信し返します。 * * 基本的にアセンブリ言語ソースをC言語に置き換えただけのものです。(若干、異なるところがあります) * 元のアセンブラソースをコメントとしてC言語ソースの上に記述してあります。 * */ // configuration bits (FOSCは発振器の種類・周波数で変化します。その他はOFFでとりあえずOKです) // __CONFIG _FOSC_HS & _WDTE_OFF & _PWRTE_OFF & _BOREN_OFF & _LVP_OFF & _CPD_OFF & _WRT_OFF & _CP_OFF #pragma config FOSC = HS // Oscillator Selection bits (HS oscillator) #pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled) #pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled) #pragma config BOREN = OFF // Brown-out Reset Enable bit (BOR disabled) #pragma config LVP = OFF // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming) #pragma config CPD = OFF // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off) #pragma config WRT = OFF // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control) #pragma config CP = OFF // Flash Program Memory Code Protection bit (Code protection off) #include <xc.h> //------------------------------------------------------------- // グローバル変数 //------------------------------------------------------------- static volatile unsigned char rxtmp; // 割り込みルーチンで使用するので volatile が必要です //------------------------------------------------------------- // 割り込み処理 //------------------------------------------------------------- void /*high_priority*/ interrupt tcInt(void) // high_priority はワーニングが出るのでコメントにしました { /* ユーザーズガイドより (コーディングの例) if (TMR0IE && TMR0IF) { // any timer 0 interrupts? TMR0IF=0; ++tick_count; } if (TMR1IE && TMR1IF) { // any timer 1 interrupts? TMR1IF=0; tick_count += 100; } */ // 受信割り込みのとき if( PIR1bits.RCIF ) { rxtmp = RCREG; // PORTB = rxtmp; } // process other interrupt sources here, if required return; } //------------------------------------------------------------- // 初期化 //------------------------------------------------------------- void init( void ) { // グローバル変数初期化 rxtmp = 0; /* ; BANK0選択 BANKSEL PORTA ;念のためI/Oポート出力を0に CLRF PORTA CLRF PORTB CLRF PORTC CLRF PORTD CLRF PORTE */ // 念のためI/Oポート出力を0に PORTA = 0; PORTB = 0; PORTC = 0; PORTD = 0; PORTE = 0; /* ;BANK1を選択 BANKSEL TRISD ;PORTDを入力に設定 MOVLW 0xff MOVWF TRISD */ // PORTDを入力に設定 TRISD = 0xff; /* ;PORTC,PORTD以外をすべて出力に設定 CLRF TRISA CLRF TRISB CLRF TRISE */ // PORTC,PORTD以外をすべて出力に設定 TRISA = 0; TRISB = 0; TRISE = 0; /* ;RS232C設定 ;RCSTA BANKSEL RCSTA MOVLW B'10010000' MOVWF RCSTA ;TXSTA BANKSEL TXSTA MOVLW B'00100110' ; MOVLW B'00100100' MOVWF TXSTA ;SPBRG BANKSEL SPBRG MOVLW D'64' MOVWF SPBRG */ // RS232C設定 RCSTA = 0x90; // B'1001_0000' TXSTA = 0x26; // B'0010_0110' SPBRG = 64; // D'64' /* ;BANK1を選択 BANKSEL TRISC ;PORTCのbit7は入力、それ以外は出力に設定 MOVLW B'10000000' MOVWF TRISC */ // PORTCのbit7は入力、それ以外は出力に設定 TRISC = 0x80; // B'1000_0000' /* ;割り込み設定 ;PIE1 BANKSEL PIE1 MOVLW B'00100000' ;とりあえず受信割り込みだけ設定 ; MOVLW B'00010000' ;送信割り込みだけ設定 ; MOVLW B'00110000' ;送受信割り込みはこっち MOVWF PIE1 ;INTCON BANKSEL INTCON MOVLW B'11000000' ;割り込み許可(bit7は全体の割り込み許可) MOVWF INTCON */ PIE1 = 0x20; // B'0010_0000' INTCON = 0xc0; // B'1100_0000' /* ;BANK0を選択 BANKSEL PORTA ;PORTA は BANK0 */ } //------------------------------------------------------------- // (rxtmpに格納されている)1文字を送信 // // 注意:アセンブリ言語ソースは w に格納されている文字を送信します //------------------------------------------------------------- void TxChar( void ) { /* ; MOVWF PORTB ;そのままPORTBへ出力 */ // PORTB = rxtmp; /* BTFSS PIR1, TXIF GOTO $-1 MOVWF TXREG */ for(;;) { if( PIR1bits.TXIF ) { TXREG = rxtmp; break; } } } //------------------------------------------------------------- // メインループ // // ※MPLAB X IDE ではmain関数はint型の戻り値を返すようですが、 // ここでは不要と思われるのでvoid型にしてあります。 //------------------------------------------------------------- void main( void ) { // 初期化 init(); /* main1: MOVF RXTMP, W BTFSC STATUS, Z ;RXTMPが0のときはmainに戻る GOTO main1 CLRF RXTMP ;受信データを0に(重複送信を防ぐため) CALL txchar ;Wの値(文字)を送信 GOTO main1 */ for(;;) { if( rxtmp ) { // 受信データがあるとき TxChar(); rxtmp = 0; } } }
アセンブリ言語のソース(コメント行)を削除すればかなりすっきりと記述できていることに気づきます。
やはりPICでもC言語で書きたいですね。
最後に、このページからダウンロードできるソースプログラムに関してはフリーウェアとします。
よろしければご自由にお使い下さい。